class HDate {
    getMaxDay(m) {
        switch (m) {
            case 1:
            case 3:
            case 5:
            case 7:
            case 8:
            case 10:
            case 12:
                return 31;
            case 2:
                return (this.year % 4 == 0 && this.year % 100 != 0 || this.year % 400 == 0) ? 29 : 28;
            case 4:
            case 6:
            case 9:
            case 11:
                return 30;
        }
    };

    /**
     * 获取日期中的年
     * @return {Number}
     */
    get Year() {
        return this.year;
    }

    /**
     * 设置日期中的年,如果范围值无效,则会设置为1970年
     * @param {Number} value 待设置的年
     */
    set Year(value) {
        if (value === undefined || value < 0 || value > 9999) {
            value = 1970;
        }
        this.year = value;
    }

    /**
     * 读取日期中的月
     */
    get Month() {
        return this.month;
    }

    /**
     * 设置日期中的日
     */
    set Month(value) {
        if (value === undefined || value < 1 || value > 12) {
            value = 1;
        }
        this.month = value;
    }

    /**
     * 读取日期中的日
     */
    get Day() {
        return this.day;
    }

    /**
     * 设置日期中的日
     */
    set Day(value) {
        if (value === undefined || value < 1 || value > this.getMaxDay(this.month)) {
            value = 1;
        }
        this.day = value;
    }

    /**
     * 安全地增减月份值,
     * @param {HDate} value 传入正数表示增加月份,传入负数表示减少月份
     */
    addMonths(value) {
        this.month += value;
        let old = this.month - 1;
        if (old > 11) {
            this.month = old % 12 + 1;
            this.year += parseInt((old + 11) / 12);
        }
        else if (old < 0) {
            this.month = (old % 12 + 12) % 12 + 1;
            this.year += parseInt((old - 11) / 12);
        }
        this.day = Math.min(this.getMaxDay(this.month), this.day);
        return this;
    };

    /**
     * 安全地增减日期中的日
     * @param {HDate} value 
     */
    addDays(value) {
        if (value > 0) {
            while (value > 0) {
                let maxDay = this.getMaxDay(this.month);
                if (this.day + value <= maxDay) {
                    this.day += value;
                    break;
                }
                else {
                    this.month++;
                    if (this.month > 12) {
                        this.month = 1;
                        this.year++;
                    }
                    value -= maxDay - (this.day - 1);
                    this.day = 1;
                }
            }
            return this;
        }
        else if (value < 0) {
            while (value < 0) {
                if (this.day + value > 0) {
                    this.day += value;
                    break;
                }
                else {
                    this.month--;
                    if (this.month <= 0) {
                        this.month = 12;
                        this.year--;
                    }
                    let maxDay = this.getMaxDay(this.month);
                    if (-value < maxDay + (this.day - 1)) {
                        this.day += maxDay + value;
                        break;
                    }
                    else {
                        value += maxDay + (this.day - 1);
                        this.day = 1;
                    }
                }
            }
            return this;
        }
    }

    /**
     * 安全得按星期增减日期
     * @param {HDate} value 
     */
    addWeeks(value) {
        return this.addDays(7 * value);
    }

    /**
     * 获取星期几
     */
    getWeekStr() {
        const weekArray = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
        return weekArray[this.getWeek()];
    };

    /**
     * 获取当前是星期几
     */
    getWeek() {
        return new Date(this.year, this.month - 1, this.day).getDay();
    };

    /**
     * 获取Unix时间戳
     * @return {Number} Unix时间戳
     */
    getUnixTimeStamp() {
        return parseInt(new Date(this.toString()).valueOf() / 1000);
    }

    /**
     * 将日期重置为今日
     */
    reset() {
        let date = new Date();
        this.year = date.getFullYear();
        this.month = date.getMonth() + 1;
        this.day = date.getDate();
    }

    getDate() {
        return new Date(this.toString());
    }

    toString(format) {
        if (typeof (format) == 'string') {
            var date = {
                "M+": this.month,
                "d+": this.day,
            };
            if (/(y+)/i.test(format)) {
                format = format.replace(RegExp.$1, (this.year + '').substr(4 - RegExp.$1.length));
            }
            for (var k in date) {
                if (new RegExp("(" + k + ")").test(format)) {
                    format = format.replace(RegExp.$1, RegExp.$1.length == 1
                        ? date[k] : ("00" + date[k]).substr(("" + date[k]).length));
                }
            }
            return format;

        } else {
            return this.year + '-' + (this.month <= 9 ? '0' : '') + this.month + '-' + (this.day <= 9 ? '0' : '') + this.day;
        }
    };


    constructor() {
        switch (arguments.length) {
            case 0:
                {
                    this.reset();
                }
                break;
            case 1:
                {
                    let date = new Date(arguments[0]);
                    this.year = date.getFullYear();
                    this.month = date.getMonth() + 1;
                    this.day = date.getDate();
                }
                break;
            case 3:
                {
                    this.Year = year;
                    this.Month = month;
                    this.Day = day;
                }
        }
    }
}

